package ar.edu.utn.frba.dds.tp.tests.vuelos;


import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import ar.edu.utn.frba.dds.tp.code.Asientos.AsientoDeVuelo;
import ar.edu.utn.frba.dds.tp.code.Asientos.ClaseAsiento;
import ar.edu.utn.frba.dds.tp.code.Asientos.EstadoAsiento;
import ar.edu.utn.frba.dds.tp.code.Asientos.UbicacionAsiento;
import ar.edu.utn.frba.dds.tp.code.adapter.LanchitaAdapter;
import ar.edu.utn.frba.dds.tp.code.adapter.OceanicAdapter;
import ar.edu.utn.frba.dds.tp.code.dateParser.FormatoSimple;
import ar.edu.utn.frba.dds.tp.code.dateParser.ParserFecha;
import ar.edu.utn.frba.dds.tp.code.filtros.PredicateClaseAsiento;
import ar.edu.utn.frba.dds.tp.code.filtros.PredicatePreciosMaxMin;
import ar.edu.utn.frba.dds.tp.code.filtros.PredicateSoloAsientosLibres;
import ar.edu.utn.frba.dds.tp.code.filtros.PredicateUbicacionAsiento;
import ar.edu.utn.frba.dds.tp.code.lugares.Lugar;
import ar.edu.utn.frba.dds.tp.code.ordenamientos.CriterioOrdenVuelos;
import ar.edu.utn.frba.dds.tp.code.ordenamientos.OrdenarPorPrecioDescendente;
import ar.edu.utn.frba.dds.tp.code.vuelos.Aerolinea;
import ar.edu.utn.frba.dds.tp.code.vuelos.BuscadorVuelos;
import ar.edu.utn.frba.dds.tp.code.vuelos.Busqueda;
import ar.edu.utn.frba.dds.tp.code.vuelos.Vuelo;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.oceanic.AerolineaOceanic;
import com.oceanic.AsientoDTO;


public class BusquedaTest {
	
	Lugar origen;
	Lugar destino;
	Date fechaSalida; 
	Aerolinea lanchita;
	Aerolinea otroAdapter;
	Aerolinea oceanic;
	ArrayList<Predicate<AsientoDeVuelo>> filtros;
	CriterioOrdenVuelos precioDescendente;
	Busqueda busqueda;
	
	@Before
	public void setUp() throws Exception {

		origen = new Lugar("BS");
		destino = new Lugar("LA");
		fechaSalida = ParserFecha.Parsear("2012-10-10",new FormatoSimple("yyyy-MM-dd"));
		
		BuscadorVuelos.getInstance().clearAerolineas();
		
		lanchita = new LanchitaAdapter();
		otroAdapter = new LanchitaAdapter();
		oceanic = new OceanicAdapter();
		Field field;
		field = OceanicAdapter.class.getDeclaredField("aerolineaOceanic");
		field.setAccessible(true);
		field.set(oceanic, new AerolineaOceanicMock());
		
        ArrayList<ClaseAsiento> clases = new ArrayList<ClaseAsiento>();
        clases.add(ClaseAsiento.TURISTA);
        clases.add(ClaseAsiento.PRIMERA);
        PredicateClaseAsiento filtroClaseTuristaPrimera = new PredicateClaseAsiento(clases);
        PredicatePreciosMaxMin filtroRangoPrecios = new PredicatePreciosMaxMin(new BigDecimal(2000), new BigDecimal(500));
        PredicateUbicacionAsiento filtroUbicacionPasillo = new PredicateUbicacionAsiento(UbicacionAsiento.PASILLO);
        PredicateSoloAsientosLibres filtroAsientosLibres = new PredicateSoloAsientosLibres();
		this.filtros = new ArrayList<Predicate<AsientoDeVuelo>>();
		filtros.add(filtroClaseTuristaPrimera);
		filtros.add(filtroUbicacionPasillo);
		filtros.add(filtroAsientosLibres);
		filtros.add(filtroRangoPrecios);
		
		this.precioDescendente = new OrdenarPorPrecioDescendente();
		
		Vuelo vueloVarios = new Vuelo("6789", "BA", "LA", null, null, null, null);
		vueloVarios.agregarAsiento(new AsientoDeVuelo(100, new BigDecimal(1000), ClaseAsiento.EJECUTIVA, UbicacionAsiento.PASILLO, EstadoAsiento.RESERVADO));
		vueloVarios.agregarAsiento(new AsientoDeVuelo(323, new BigDecimal(3000), ClaseAsiento.PRIMERA, UbicacionAsiento.CENTRO, EstadoAsiento.COMPRADO));
		vueloVarios.agregarAsiento(new AsientoDeVuelo(302,new BigDecimal(1250),ClaseAsiento.PRIMERA,UbicacionAsiento.PASILLO,EstadoAsiento.DISPONIBLE));
		vueloVarios.agregarAsiento(new AsientoDeVuelo(932, new BigDecimal(400), ClaseAsiento.EJECUTIVA, UbicacionAsiento.PASILLO, EstadoAsiento.DISPONIBLE));
		vueloVarios.agregarAsiento(new AsientoDeVuelo(423, new BigDecimal(1900),ClaseAsiento.PRIMERA,UbicacionAsiento.PASILLO,EstadoAsiento.DISPONIBLE));
		Vuelo vueloClaseEjecutiva = new Vuelo("1234", "BA", "LA", null, null, null, null);
		vueloClaseEjecutiva.agregarAsiento(new AsientoDeVuelo(100, new BigDecimal(1000), ClaseAsiento.EJECUTIVA, UbicacionAsiento.PASILLO, EstadoAsiento.DISPONIBLE));
		Vuelo vueloUbicacionVentana = new Vuelo("1234", "BA", "LA", null, null, null, null);
		vueloUbicacionVentana.agregarAsiento(new AsientoDeVuelo(100, new BigDecimal(1000), ClaseAsiento.TURISTA, UbicacionAsiento.VENTANA, EstadoAsiento.DISPONIBLE));
		Vuelo vueloSinAsientosLibres = new Vuelo("1234", "BA", "LA", null, null, null, null);
		vueloSinAsientosLibres.agregarAsiento(new AsientoDeVuelo(100, new BigDecimal(1000), ClaseAsiento.TURISTA, UbicacionAsiento.PASILLO, EstadoAsiento.RESERVADO));
		Vuelo vueloPrecio3000 = new Vuelo("1234", "BA", "LA", null, null, null, null);
		vueloPrecio3000.agregarAsiento(new AsientoDeVuelo(100, new BigDecimal(3000), ClaseAsiento.TURISTA, UbicacionAsiento.PASILLO, EstadoAsiento.DISPONIBLE));
		
		this.busqueda = new Busqueda(origen, destino, fechaSalida);
		ArrayList<Vuelo> vuelos = new ArrayList<Vuelo>();
		vuelos.add(vueloClaseEjecutiva);
		vuelos.add(vueloUbicacionVentana);
		vuelos.add(vueloSinAsientosLibres);
		vuelos.add(vueloPrecio3000);
		vuelos.add(vueloVarios);
		this.busqueda.setVuelos(vuelos);
		
	}
	
	
	@Test
	public void testVuelosBusquedaNoVacios (){
		
		Busqueda busquedaAProbar = new Busqueda(origen, destino, fechaSalida);
		
		Assert.assertFalse(busquedaAProbar.getVuelos().isEmpty());
	}
	
	@Test
	public void testBuscarVuelosConVariosFiltros() {
		Assert.assertEquals(1, this.busqueda.getVuelos(filtros).size());
	}
	
	@Test
	public void testBuscarYOrdenar() {
		Assert.assertEquals(new BigDecimal(3000), this.busqueda.getVuelos(precioDescendente).get(4).getAsientos().get(0).getPrecio());
	}
	
	@Test
	public void testBusquedaTieneVuelosDeOceanic() {
		Busqueda unaBusqueda = new Busqueda(origen, destino, fechaSalida);
		
		Predicate<Vuelo> tieneOceanic = new Predicate<Vuelo>() {
			@Override
			public boolean apply(Vuelo vuelo) {
				return (vuelo.getAerolinea() instanceof OceanicAdapter);
			}
		};
		
		
		Assert.assertTrue(Iterables.any(unaBusqueda.getVuelos(), tieneOceanic));
	}
	
	@Test
	public void testBusquedaTieneVuelosDeLanchita(){
		
		Busqueda unaBusqueda = new Busqueda(new Lugar("EZE"), new Lugar("USA"), ParserFecha.Parsear("2012-12-20",new FormatoSimple("yyyy-MM-dd")));
		
		Predicate<Vuelo> tieneLanchita = new Predicate<Vuelo>() {
			@Override
			public boolean apply(Vuelo vuelo) {
				return (vuelo.getAerolinea() instanceof LanchitaAdapter);
			}
		};
		
		Assert.assertTrue(Iterables.any(unaBusqueda.getVuelos(), tieneLanchita));
	}
	
	@Test
	public void testBuscadorVuelosUnaSolaAerolineaXAdapter(){
		BuscadorVuelos buscador = BuscadorVuelos.getInstance();
		Assert.assertEquals(2, buscador.getAerolineas().size());
	}

final class AerolineaOceanicMock extends AerolineaOceanic {
	
	public List<AsientoDTO> asientosDisponiblesParaOrigenYDestino(String origen, String destino, String fechaDeSalida) {
		List<AsientoDTO> asientos = new ArrayList<AsientoDTO>();
		asientos.add(new AsientoDTO("OC100",10,"15/08/2012","17/08/2012","10:35","05:35",new BigDecimal("3150.98"),"Ejecutiva","Pasillo",false,"BS_","SLA"));
		asientos.add(new AsientoDTO("OC100",11,"15/08/2012","17/08/2012","10:35","05:35",new BigDecimal("3150.98"),"Ejecutiva","Pasillo",false,"BS_","SLA"));
		asientos.add(new AsientoDTO("OC101",8,"15/08/2012","17/08/2012","10:35","05:35",new BigDecimal("3150.98"),"Ejecutiva","Pasillo",false,"BS_","SLA"));
		return asientos;
	}
	
}
	
	@After
	public void tearDown(){
		BuscadorVuelos.getInstance().clearAerolineas();
	}
	
}
